﻿using System.Net.Http.Headers;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;

namespace KS.DataWrapper.DataWrapper.LINQ
{
    public class WebApiQueryProvider<T> : QueryProvider
    {


        private string GetRequestUrl()
        {
            return string.Format("{0}/{1}", KS.DataWrapper.Config.WebApiConfig.BaseUrl, typeof(T).Name);
        }

        private readonly HttpClient httpClient;

        public WebApiQueryProvider()
        {
            this.httpClient = new HttpClient();
            httpClient.BaseAddress = new Uri(KS.DataWrapper.Config.WebApiConfig.BaseUrl);
            this.httpClient = new HttpClient(new HttpClientHandler
            {
                AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
            });
            this.httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }

        public WebApiQueryProvider(HttpClient httpClient)
        {
            this.httpClient = httpClient;
        }

        public override string GetQueryText(Expression expression)
        {
            return this.Translate(expression);
        }

        private IEnumerable GetResiltFromServer(Expression expression, Type type)
        {
        //    Expression.b

         //  Expression.MakeMemberAccess(expression)

          //  var ololo = this.GetQueryText(expression);

            string query = expression.ToString();
            bool isCount = false;

          

            if (query.Contains(".Count()"))
            {
                //query = query.Replace(".Count()", "");
                isCount = true;
            }

            var task = Task.Run(() => httpClient.GetAsync(GetRequestUrl() + "/Query?exp=" + query));

            var response = task.Result;

            response.EnsureSuccessStatusCode(); // Throw on error code. 

            //if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
            if (!isCount)
            {
                var task2 = Task.Run(() => response.Content.ReadAsAsync<IEnumerable<T>>());

                var rez = task2.Result;

                return rez; 
            }
            else
            {
                var task2 = Task.Run(() => response.Content.ReadAsAsync<List<int>>());

                var rez = task2.Result;

                return rez; 
            }

            
           
        }

        public TResult Execute<TResult>(Expression expression)
        {

            bool isCollection = typeof(TResult).IsGenericType && typeof(TResult).GetGenericTypeDefinition() == typeof(IEnumerable<>);
            Type itemType = isCollection // TResult is an IEnumerable`1 collection.
                            ? typeof(TResult).GetGenericArguments().Single()
                            // TResult is not an IEnumerable`1 collection, but a single item.
                            : typeof(TResult);
            //IQueryable queryable = Activator.CreateInstance(
            //    typeof(Query<>).MakeGenericType(itemType), this, expression) as IQueryable;

            IEnumerable queryResult = GetResiltFromServer(expression, itemType);


      
            var result = isCollection ? (TResult)queryResult // Returns an IEnumerable`1 collection.
                   : queryResult.OfType<TResult>().SingleOrDefault(); // Returns a single item.
 

            return result;
        }
         


        public override object Execute(Expression expression)
        {
            if(expression.ToString().Contains(".Count()"))
            {
                return Execute<int>(expression);
            }
            else
            {
                return Execute<IEnumerable<T>>(expression);
            }

            
            string query = expression.ToString();

            //if (query.Contains(".Count()"))
            //{
            //    query = query.Replace(".Count()", "");
            //}

            var task = Task.Run(() => httpClient.GetAsync(GetRequestUrl() + "/Query?exp=" + query));

            var response = task.Result;

            response.EnsureSuccessStatusCode(); // Throw on error code. 

            bool isCount = false;
            if (query.EndsWith(".Count()"))
            {
                var task2 = Task.Run(() => response.Content.ReadAsAsync<long>());

                var rez = task2.Result;

                return rez;
            }
            else
            {
                var task2 = Task.Run(() => response.Content.ReadAsAsync<object>());

                var rez = task2.Result;

                return rez;
            }
        }

        public override long Count()
        {
            var task = Task.Run(() => httpClient.GetAsync(string.Format("{0}/Count", this.GetRequestUrl())));

            var response = task.Result;

            response.EnsureSuccessStatusCode(); // Throw on error code. 

            var task2 = Task.Run(() => response.Content.ReadAsAsync<long>());

            var rez = task2.Result;

            return rez;
        }

        private string Translate(Expression expression)
        {
            return new QueryTranslator().Translate(expression);
        }
    }
}